package com.hex.ds.hdrs.log.service;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hex.ds.hdrs.agent.po.AgentConf;
import com.hex.ds.hdrs.agent.po.AgentHeartbeatLog;
import com.hex.ds.hdrs.agent.service.AgentHeartbeatLogService;
import com.hex.ds.hdrs.agent.service.AgentSession;
import com.hex.ds.hdrs.agent.vo.ResponseInf;
import com.hex.ds.hdrs.app.po.AppConf;
import com.hex.ds.hdrs.app.service.AppSession;
import com.hex.ds.hdrs.center.po.CenterConf;
import com.hex.ds.hdrs.center.service.CenterManager;
import com.hex.ds.hdrs.center.vo.HeartBeatReq;
import com.hex.ds.hdrs.center.vo.RegisterReq;
import com.hex.ds.hdrs.common.constant.Const;
import com.hex.ds.hdrs.common.constant.HttpConst;
import com.hex.ds.hdrs.log.po.RunningStateLog;
import com.hex.ds.hdrs.log.po.ServerInteractLog;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class LogService {

    @Autowired
    private CenterManager centerManager;

    @Value("${logging.saveServerLog}")
    private boolean saveServerLog;

    //配置文件中中心ip
    @Value("${center.centerIp}")
    private String centerIp;

    @Autowired
    private ServerInteractLogService serverInteractLogService;
    @Autowired
    private RunningStateLogService runningStateLogService;
    @Autowired
    private AgentHeartbeatLogService agentHeartbeatLogService;

    /**
     * 注册成功 添加运行日志
     *
     * @param registerReq
     */
    public void addRegisterSuccRunLog(RegisterReq registerReq) {
        log.info("注册成功 添加运行日志【LogHelper.addRunningStateLog】开始======》");
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_AGENT);
        runningStateLog.setSrcCode(registerReq.getReqCode());
        runningStateLog.setSrcName(registerReq.getAgentName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_INFO);
        runningStateLog.setRemindContent(registerReq.getAgentName() + "上线!");
        runningStateLog.setRemindTitle(Const.AGENT_WARN_ON_LINE_NAME);
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 注册失败 添加运行日志
     *
     * @param registerReq
     */
    public void addRegisterFailRunLog(RegisterReq registerReq) {
        log.info("注册失败 添加运行日志【LogHelper.addRunningStateLog】开始======》");
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_AGENT);
        runningStateLog.setSrcCode(registerReq.getReqCode());
        runningStateLog.setSrcName(registerReq.getAgentName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_ERROR);
        runningStateLog.setRemindContent("节点注册失败!");
        runningStateLog.setRemindTitle("节点注册");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 失败
     */
    public void centerDownFailLog(CenterConf centerConf) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_CENTER);
        runningStateLog.setSrcCode(centerConf.getCenterCode());
        runningStateLog.setSrcName(centerConf.getCenterName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_ERROR);
        runningStateLog.setRemindContent("中心从MASTER下线失败!");
        runningStateLog.setRemindTitle("中心从MASTER下线");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 中心初始化成功
     */
    public void centerInitSuccLog(CenterConf centerConf) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_CENTER);
        runningStateLog.setSrcCode(centerConf.getCenterCode());
        runningStateLog.setSrcName(centerConf.getCenterName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_INFO);
        runningStateLog.setRemindContent("中心初始化成功!");
        runningStateLog.setRemindTitle("中心初始化");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 中心初始化失败
     */
    public void centerInitFailLog(CenterConf centerConf) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_CENTER);
        runningStateLog.setSrcCode(centerConf.getCenterCode());
        runningStateLog.setSrcName(centerConf.getCenterName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_ERROR);
        runningStateLog.setRemindContent("中心初始化失败!");
        runningStateLog.setRemindTitle("中心初始化");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 中心下线成功
     */
    public void centerDownSuccLog(CenterConf centerConf) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_CENTER);
        runningStateLog.setSrcCode(centerConf.getCenterCode());
        runningStateLog.setSrcName(centerConf.getCenterName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_WARN);
        runningStateLog.setRemindContent("中心从MASTER下线成功!");
        runningStateLog.setRemindTitle("中心从MASTER下线");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * MASTER中心节点数异常
     */
    public void centerAgentNumExceptionLog(CenterConf centerConf) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_CENTER);
        runningStateLog.setSrcCode(centerConf.getCenterCode());
        runningStateLog.setSrcName(centerConf.getCenterName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_ERROR);
        runningStateLog.setRemindContent("MASTER中心有效节点数异常，设定时间内急剧下降!");
        runningStateLog.setRemindTitle("中心有效节点数");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 获取应用继续日志信息
     *
     * @param appSession
     * @return
     */
    public void continueAppLog(AppSession appSession) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_APP);
        runningStateLog.setSrcCode(appSession.getAppCode());
        runningStateLog.setSrcName(appSession.getAppName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_INFO);
        runningStateLog.setRemindContent("应用启用!");
        runningStateLog.setRemindTitle("应用状态改变");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 获取应用停用日志信息
     *
     * @param appSession
     * @return
     */
    public void stopAppLog(AppSession appSession) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_APP);
        runningStateLog.setSrcCode(appSession.getAppCode());
        runningStateLog.setSrcName(appSession.getAppName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_INFO);
        runningStateLog.setRemindContent("应用停用!");
        runningStateLog.setRemindTitle("应用状态改变");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 创建appSession 日志信息
     *
     * @param appConf
     * @return
     */
    public void crtAppLog(AppConf appConf) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_APP);
        runningStateLog.setSrcCode(appConf.getAppCode());
        runningStateLog.setSrcName(appConf.getAppName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_INFO);
        runningStateLog.setRemindContent("创建应用Session成功!");
        runningStateLog.setRemindTitle("创建应用Session");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 创建appSession异常 日志信息
     *
     * @param appConf
     * @return
     */
    public void crtErrorAppLog(AppConf appConf, String error) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_APP);
        runningStateLog.setSrcCode(appConf.getAppCode());
        runningStateLog.setSrcName(appConf.getAppName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_ERROR);
        runningStateLog.setRemindContent("创建应用Session异常: " + error.substring(0, 2000));
        runningStateLog.setRemindTitle("创建应用Session");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 创建appSession警告 日志信息
     *
     * @param appConf
     * @return
     */
    public void crtWarnAppLog(AppConf appConf) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_APP);
        runningStateLog.setSrcCode(appConf.getAppCode());
        runningStateLog.setSrcName(appConf.getAppName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_WARN);
        runningStateLog.setRemindContent("创建应用Session警告:应用下无节点!");
        runningStateLog.setRemindTitle("创建应用Session");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 获取节点停用日志信息
     *
     * @param agentSession
     * @return
     */
    public void stopAgentLog(AgentSession agentSession, String remindContent) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_AGENT);
        runningStateLog.setSrcCode(agentSession.getAgentCode());
        runningStateLog.setSrcName(agentSession.getAgentName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_WARN);
        runningStateLog.setRemindContent(remindContent);
        runningStateLog.setRemindTitle(Const.AGENT_WARN_OFF_LINE_NAME);
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 获取节点继续日志信息
     *
     * @param agentSession
     * @return
     */
    public void continueAgentLog(AgentSession agentSession) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_AGENT);
        runningStateLog.setSrcCode(agentSession.getAgentCode());
        runningStateLog.setSrcName(agentSession.getAgentName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_INFO);
        runningStateLog.setRemindContent("节点启用!");
        runningStateLog.setRemindTitle("节点状态改变");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 应用资源不足警告 日志信息
     *
     * @return
     */
    public void resNotEnoughAppLog(AppConf appConf, String warnInfo) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_APP);
        runningStateLog.setSrcCode(appConf.getAppCode());
        runningStateLog.setSrcName(appConf.getAppName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_INFO);
        runningStateLog.setRemindContent("应用资源达到最大使用率: " + warnInfo);
        runningStateLog.setRemindTitle("应用资源等待释放");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 节点资源不足 日志信息
     *
     * @param warnInfo
     * @return
     */
    public void resNotEnoughAgentLog(AgentConf agentConf, String warnInfo) {
        RunningStateLog runningStateLog = new RunningStateLog();
        runningStateLog.setSrcType(Const.TYPE_AGENT);
        runningStateLog.setSrcCode(agentConf.getAgentCode());
        runningStateLog.setSrcName(agentConf.getAgentName());
        runningStateLog.setCrtTs(DateUtil.now());
        runningStateLog.setWarnLevel(Const.WARN_LEVEL_INFO);
        runningStateLog.setRemindContent("节点资源达到最大使用率: " + warnInfo);
        runningStateLog.setRemindTitle("节点资源等待释放");
        this.runningStateLogService.insert(runningStateLog);
    }

    /**
     * 中心到agent通信日志
     *
     * @param obj
     * @param url
     * @param rsp
     */
    public void centerToAgent(Object obj, String url, ResponseInf rsp) {
        try {
            ServerInteractLog log = new ServerInteractLog();
            String code = rsp == null ? "400" : rsp.getCode();
            if ("200".equals(code)) {
                log.setReqResult("1");
            } else {
                log.setReqResult("2");
                log.setFailReason(rsp == null ? "与agent通信异常" : rsp.getMsg());
            }
            log.setInteractType(HttpConst.CENTER_TO_AGENT);
            log.setFromCode(centerManager.getCenterCode());
            log.setFromIp(centerIp);
            log.setFromTs(DateUtil.now());
            log.setFromJson(obj == null ? "" : JSONObject.toJSON(obj).toString());
            log.setReqUrl(url);
            log.setToIp(centerIp);
            log.setBackTs(DateUtil.now());
            log.setBackJson(rsp == null ? "" : JSONObject.toJSON(rsp).toString());
            if (saveServerLog) {
                serverInteractLogService.addLog(log);
            }
        } catch (Exception e) {
            log.error("【centerToAgent】异常: {}", e.getMessage(),e);

        }
    }


    /**
     * 新增节点心跳日志
     *
     * @param heartBeatReq
     * @return
     */
    public void addAgentHeartbeatLog(HeartBeatReq heartBeatReq, AgentSession agentSession) {
        AgentHeartbeatLog agentHeartbeatLog = new AgentHeartbeatLog();

        //根据节点编码和节点IP判断日志中是否已经存在，存在更新否则新增
        Map map = new HashMap();
        map.put("agentCode", heartBeatReq.getReqCode());
        map.put("agentIp", heartBeatReq.getIp());
        List<AgentHeartbeatLog> list = this.agentHeartbeatLogService.qryHbLog(map);
        if (CollectionUtils.isNotEmpty(list)) {
            //存在
            AgentHeartbeatLog log = list.stream().reduce((a, b) -> DateUtil.parse(a.getCrtTs()).before(DateUtil.parse(b.getCrtTs())) ? a : b).orElseThrow(RuntimeException::new);
            this.setAgentHeartBeatLogObj(log, heartBeatReq, agentSession);
            //修改
            this.agentHeartbeatLogService.edit(log);
        } else {
            //不存在
            this.setAgentHeartBeatLogObj(agentHeartbeatLog, heartBeatReq, agentSession);
            //新增
            this.agentHeartbeatLogService.addLog(agentHeartbeatLog);
        }
    }

    private void setAgentHeartBeatLogObj(AgentHeartbeatLog agentHeartbeatLog, HeartBeatReq heartBeatReq, AgentSession agentSession) {
        agentHeartbeatLog.setAgentCode(heartBeatReq.getReqCode());
        agentHeartbeatLog.setCrtTs(DateUtil.now());
        agentHeartbeatLog.setSendTs(DateUtil.now());
        agentHeartbeatLog.setAgentIp(heartBeatReq.getIp());
        agentHeartbeatLog.setCenterCode(centerManager.getCenterCode());
        agentHeartbeatLog.setCenterIp(centerManager.getCenterIp());
        agentHeartbeatLog.setMemoryInfo(JSON.toJSONString(heartBeatReq.getAgentMem()));
        agentHeartbeatLog.setCpuInfo(JSON.toJSONString(heartBeatReq.getAgentCpu()));
        agentHeartbeatLog.setSwapInfo(JSON.toJSONString(heartBeatReq.getAgentMem()));
        agentHeartbeatLog.setFileSysInfo(JSON.toJSONString(heartBeatReq.getAgentFileSys()));
        agentHeartbeatLog.setIoSaturability(heartBeatReq.getAgentCpu().getCpuWait() + "%");
        agentHeartbeatLog.setDataJson(JSON.toJSONString(heartBeatReq));
        agentHeartbeatLog.setCurResNum(heartBeatReq.getUsedResNum());
        agentHeartbeatLog.setCurConcurrenceNum(heartBeatReq.getUsedConcurrentNum());
        agentHeartbeatLog.setAllResNum(agentSession.getAgentConf().getResNum());
        agentHeartbeatLog.setAllConcurrenceNum(agentSession.getAgentConf().getConcurrentNum());
        agentHeartbeatLog.setAgentName(heartBeatReq.getAgentName());
    }

}
